home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / TurboTCP 2.1 / TurboTCP core / CTCPAsyncCall.cp next >
Encoding:
Text File  |  1995-01-05  |  9.0 KB  |  325 lines  |  [TEXT/MMCC]

  1. //
  2. // CTCPAsyncCall.cp
  3. //
  4. //    TurboTCP library
  5. //    TCP asynchronous call class
  6. //
  7. //    Copyright © 1993-95, FrostByte Design / Eric Scouten
  8. //
  9.  
  10. #include "CTCPAsyncCall.h"
  11.  
  12. #include "CTCPDriver.h"
  13. #include "CTCPStream.h"
  14.  
  15. #if !TurboTCP_UH2
  16.     #define TCPIOCompletionUPP TCPIOCompletionProc
  17. #endif
  18.  
  19.  
  20. //***********************************************************
  21. //
  22. // UPP for completion procedure (corrects a bug in <TCPPB.h>)
  23. //
  24.  
  25. #if TurboTCP_CFM
  26.     enum {
  27.         TTCP_uppTCPIOCompletionProcInfo = kRegisterBased            // •• was kCStackBased in <TCPPB.h>
  28.              | REGISTER_ROUTINE_PARAMETER(1, kRegisterA0, SIZE_CODE(sizeof(struct TCPiopb*)))
  29.     };
  30.     UniversalProcPtr CTCPAsyncCall::completionProcUPP = nil;
  31. #endif
  32.  
  33.  
  34. // –– initiate, process TCP call ––
  35.  
  36. //***********************************************************
  37.  
  38. OSErr CTCPAsyncCall::DoAsyncCall                // private method
  39.     (short    theCsCode,                    // TCP operation code
  40.     TCPiopb*    theParamBlockPtr)                // parameter block for TCP call
  41.  
  42.     // Fills in the standard parameters for a TCP Device Manager call and executes the call.
  43.     // Returns the result code.
  44.  
  45. {
  46.     ::BlockMoveData(theParamBlockPtr, &itsiopb.itsParamBlock, sizeof (TCPiopb));
  47.     return DoAsyncCall(theCsCode);
  48. }
  49.  
  50. OSErr CTCPAsyncCall::DoAsyncCall                // private version for use by DispatchNoCopyRcv
  51.     (short theCsCode)                        // TCP operation code
  52.  
  53. {
  54.     #if GENERATINGCFM                        // seems to be buggy here…
  55.         itsiopb.itsParamBlock.ioCompletion = (TCPIOCompletionUPP) completionProcUPP;
  56.     #else
  57.         itsiopb.itsParamBlock.ioCompletion = (TCPIOCompletionUPP) CompletionProc;
  58.     #endif
  59.     itsiopb.itsParamBlock.ioCRefNum = (CTCPDriver::gTCPDriver)->GetTCPRefNum();
  60.     itsiopb.itsParamBlock.csCode = theCsCode;
  61.     itsiopb.itsQueue = &((CTCPDriver::gTCPDriver)->asyncQueue);
  62.     ::PBControlAsync((ParmBlkPtr) &itsiopb.itsParamBlock);
  63.     return itsiopb.itsParamBlock.ioResult;
  64. }
  65.  
  66.  
  67. //***********************************************************
  68.  
  69. void CTCPAsyncCall::ProcessCompletion()
  70.  
  71.     // Respond to completion of this TCP call and all calls following it in the completion loop.
  72.     // After running through this loop, disposes of the call object, UNLESS it was a successful
  73.     // auto-receive call.
  74.  
  75. {
  76.     Boolean disposeWhenDone;
  77.  
  78.     
  79.     // dispatch to general completion routine or to optimized routine for no-copy-receive calls
  80.  
  81.     Try_ {
  82.         if (itsiopb.itsParamBlock.csCode == TCPNoCopyRcv)
  83.             disposeWhenDone = DispatchNoCopyRcv();
  84.         else
  85.             disposeWhenDone = Dispatch();
  86.         if (disposeWhenDone) {
  87.             itsStream.ProcessAsyncCompletion(this);
  88.             delete this;
  89.         }
  90.     }
  91.     Catch_(err) {
  92.         itsStream.ProcessAsyncCompletion(this);
  93.         delete this;
  94.         DontThrowSame_;
  95.     }
  96.     EndCatch_;
  97.  
  98. }
  99.  
  100. //***********************************************************
  101.  
  102. Boolean CTCPAsyncCall::Dispatch()                // private method
  103.  
  104.     // Called by ProcessCompletion to report back to the CTCPStream object. Does not dispose
  105.     // of object. Also, does not handle TCPNoCopyRcv commands (see DispatchNoCopyRcv
  106.     // method below). Returns true if the call object should be disposed when done.
  107.  
  108. {
  109.     wdsEntry* WDSPtr;
  110.  
  111.     if (itsiopb.itsParamBlock.ioResult) {
  112.  
  113.         // command failed, what was it?
  114.  
  115.         switch (itsiopb.itsParamBlock.csCode) {
  116.  
  117.             case TCPPassiveOpen:
  118.             case TCPActiveOpen:
  119.                 itsStream.HandleOpenFailed(itsiopb.itsParamBlock.ioResult);
  120.                 break;
  121.                 
  122.             case TCPSend:
  123.                 itsStream.HandleSendFailed((wdsEntry*) itsiopb.itsParamBlock.csParam.send.wdsPtr,
  124.                     itsiopb.itsParamBlock.csParam.open.security,
  125.                     itsiopb.itsParamBlock.csParam.open.timeToLive, itsiopb.itsParamBlock.ioResult);
  126.                 break;
  127.  
  128.             case TCPRcv:
  129.                 if (itsiopb.itsParamBlock.ioResult == connectionClosing)
  130.                     break;
  131.             
  132.             case TCPClose:
  133.                 if (itsiopb.itsParamBlock.ioResult == connectionDoesntExist)
  134.                     break;
  135.  
  136.             case TCPRcvBfrReturn:
  137.                 if (itsiopb.itsParamBlock.ioResult == invalidRDS)
  138.                     break;
  139.  
  140.             default:
  141.                 itsStream.HandleTCPError(itsiopb.itsParamBlock.ioResult, itsiopb.itsParamBlock.csCode);
  142.                 break;
  143.  
  144.         }
  145.     }
  146.     else {
  147.  
  148.         // no error, dispatch success — what type of call was this anyway?
  149.  
  150.         switch (itsiopb.itsParamBlock.csCode) {
  151.     
  152.             case TCPPassiveOpen:
  153.             case TCPActiveOpen:
  154.                 itsStream.HandleOpened();
  155.                 itsStream.StartAutoReceive();
  156.                 break;
  157.     
  158.             case TCPSend:
  159.                 WDSPtr = (wdsEntry*) itsiopb.itsParamBlock.csParam.send.wdsPtr;
  160.                 itsStream.HandleDataSent(WDSPtr, itsiopb.itsParamBlock.csParam.open.security,
  161.                     itsiopb.itsParamBlock.csParam.open.timeToLive);
  162.                 break;
  163.  
  164.             case TCPRcv:
  165.                 if (itsiopb.itsParamBlock.csParam.receive.urgentFlag)
  166.                     itsStream.RcvUrgentBegin();
  167.                 if (itsiopb.itsParamBlock.csParam.receive.markFlag)
  168.                     itsStream.RcvUrgentMark();
  169.                 itsStream.HandleDataArrived(itsiopb.itsParamBlock.csParam.receive.rcvBuff,
  170.                                         itsiopb.itsParamBlock.csParam.receive.rcvBuffLen,
  171.                                           itsStream.RcvUrgentStatus());
  172.                 break;
  173.  
  174.             case TCPClose:
  175.                 itsStream.HandleClosed();
  176.                 break;
  177.  
  178.             case TCPRcvBfrReturn:
  179.  
  180.                 // if auto-receiving, re-issue the TCPNoCopyRcv command with same paramters
  181.                 
  182.                 if ((itsiopb.itsParamBlock.csParam.open.options[36]) && (itsStream.hasSessionOpen)) {
  183.                     itsiopb.itsParamBlock.csParam.receive.rdsLength = itsiopb.itsParamBlock.csParam.open.options[36];
  184.                     DoAsyncCall(TCPNoCopyRcv);
  185.                     return false;                // make sure call object stays around
  186.                 }
  187.                 else
  188.                     ::DisposePtr(itsiopb.itsParamBlock.csParam.receive.rdsPtr);
  189.                 break;
  190.             
  191.         }    // switch
  192.     }        // if…else
  193.     
  194.     return true;                                // always dispose of call object when done
  195.  
  196. }
  197.  
  198.  
  199. //***********************************************************
  200.  
  201. Boolean CTCPAsyncCall::DispatchNoCopyRcv()                // private method
  202.  
  203.     // Optimized routine to handle completion of TCPNoCopyRcv calls.
  204.     // Returns true if the call object should be disposed when done.
  205.  
  206. {
  207.     rdsEntry* RDSPtr;
  208.  
  209.  
  210.     // respond to error condition
  211.  
  212.     if (itsiopb.itsParamBlock.ioResult) {
  213.         if ((itsiopb.itsParamBlock.ioResult != connectionClosing)
  214.           && (itsiopb.itsParamBlock.ioResult != connectionDoesntExist))
  215.             itsStream.HandleTCPError(itsiopb.itsParamBlock.ioResult, itsiopb.itsParamBlock.csCode);
  216.         ::DisposePtr(itsiopb.itsParamBlock.csParam.receive.rdsPtr);
  217.         return true;                            // always dispose when call fails
  218.     }
  219.  
  220.  
  221.     // update urgent flags
  222.  
  223.     if (itsiopb.itsParamBlock.csParam.receive.urgentFlag)
  224.         itsStream.RcvUrgentBegin();
  225.     if (itsiopb.itsParamBlock.csParam.receive.markFlag)
  226.         itsStream.RcvUrgentMark();
  227.  
  228.  
  229.     // run through RDS and process each block of data
  230.  
  231.     RDSPtr = (rdsEntry*) itsiopb.itsParamBlock.csParam.receive.rdsPtr;
  232.     
  233.     while ((*RDSPtr).length) {
  234.         itsStream.HandleDataArrived((*RDSPtr).ptr, (*RDSPtr).length, itsStream.rcvUrgent);
  235.         RDSPtr++;
  236.     }
  237.  
  238.  
  239.     // return the buffers to MacTCP
  240.     
  241.     DoAsyncCall(TCPRcvBfrReturn);
  242.  
  243.  
  244.     // if auto-receiving, the call will be reissued when the BfrReturn call is completed
  245.     
  246.     return false;                // keep call object around
  247.  
  248. }
  249.  
  250. //***********************************************************
  251.  
  252. void CTCPAsyncCall::GetCompletionProc()            // private static method
  253.  
  254.     // If running on a PowerPC, get the completion procedure resource and build a routine
  255.     // descriptor. Since the completion proc is called frequently from the Device Driver and
  256.     // MacTCP (which are emulated 68K code), we provide a 68K completion proc to avoid
  257.     // the overhead of the mode switch. Therefore, this routine builds a fat routine descriptor
  258.     // containing the 68K and PPC versions. (The 68K version is found in the code resource
  259.     // 'Ttcp' 23000. It is the 68K equivalent of the completion procedure below.)
  260.  
  261.     // This routine does nothing in 68K builds (note the #ifdef/#endif that bracket the
  262.     // routine).
  263.  
  264. {
  265. #if TurboTCP_PPC
  266.  
  267.     Handle    codeHandle;
  268.     Ptr        codeEntry;
  269.  
  270.     codeHandle = ::GetResource('Ttcp', 23000);
  271.     ThrowIfNil_(codeHandle);
  272.     ::DetachResource(codeHandle);
  273.     codeEntry = *codeHandle;
  274.  
  275.     completionProcUPP = ::NewFatRoutineDescriptor((ProcPtr) codeEntry, (ProcPtr) &CompletionProc,
  276.                                         TTCP_uppTCPIOCompletionProcInfo);
  277.     ThrowIfNil_(completionProcUPP);
  278.  
  279. #endif
  280. }
  281.  
  282.  
  283. //***********************************************************
  284. //
  285. // A few silly changes to make our completion routines work.
  286. //
  287.  
  288. #if TurboTCP_68K
  289.  
  290. #ifdef __MWERKS__
  291.     #pragma profile off
  292.     #pragma a6frames off
  293. #endif
  294.  
  295. struct TurboTCPiopb* GetTheCall();
  296. #pragma parameter __A0 GetTheCall()
  297. extern struct TurboTCPiopb* GetTheCall() = 0x2048;            // MOVEA.L A0,A0
  298.  
  299.  
  300. //***********************************************************
  301.  
  302. pascal void CTCPAsyncCall::CompletionProc()
  303.  
  304.     // The asynchronous completion routine. Recieves notification that any asynchronous
  305.     // TCP I/O operation has been completed. This routine is used for all TCP calls placed by
  306.     // CTCPAsyncCall::DoAsyncCall.
  307.  
  308.     // Send notification to the TCP driver object that this call has been completed. The driver
  309.     // then queues the call for processing at the next event loop.
  310.  
  311.     // The struct TurboTCPiopb includes a pointer to the CTCPDriver queue so that we don’t
  312.     // need to access application globals in this loop. This improves performance, and
  313.     // also permits us to use a 68K code resource in an otherwise PowerPC environment
  314.     // to avoid the performance hit of mode switches.
  315.     
  316.     // *** Runs at interrupt level. ***
  317.  
  318. {
  319.     struct TurboTCPiopb* iopb = GetTheCall();
  320.     ::Enqueue((QElemPtr) &(iopb->itsQElem), iopb->itsQueue);
  321.             // CTCPDriver::ProcessNetEvents will pick this up later
  322. }
  323.  
  324. #endif    // TurboTCP_68K
  325.